package com.zhang.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhang.entity.SysMenu;
import com.zhang.entity.SysRole;
import com.zhang.entity.SysUser;
import com.zhang.entity.SysUserRole;
import com.zhang.mapper.SysRoleMapper;
import com.zhang.mapper.SysUserMapper;
import com.zhang.mapper.SysUserRoleMapper;
import com.zhang.service.SysMenuService;
import com.zhang.service.SysRoleService;
import com.zhang.service.SysUserRoleService;
import com.zhang.service.SysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 张立松
 * @since 2022-12-22
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    SysRoleService sysRoleService;
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    SysMenuService sysMenuService;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    RedisUtil redisUtil;

    @Override
    public SysUser getByUsername(String username) {
        return getOne(new QueryWrapper<SysUser>().eq("username",username));
    }

    //获取用户权限信息（角色、菜单权限），角色字符串要加前缀ROLE_，springsecurity才能识别，例：ROLE_admin。
    //返回结果为拼接的字符串，不同角色和权限用逗号隔开
    @Override
    public String getAuthorityInfo(Long userId) {
        String authority = "";
        SysUser user = sysUserMapper.selectById(userId);

        if(redisUtil.hasKey("GrantedAuthority:"+user.getUsername())){   //如果缓存中有权限信息则直接返回，避免频繁的查库
            authority = (String) redisUtil.get("GrantedAuthority:"+user.getUsername());
        }else {
            //获取用户的角色
            List<SysRole> roles = sysRoleService.list(new QueryWrapper<SysRole>()
                    .inSql("id", "select role_id from sys_user_role where user_id=" + userId));
            if(roles.size() > 0){
                for(SysRole r : roles){
                    authority = authority + "ROLE_"+r.getCode()+",";
                }
            }

            //获取菜单操作编码
            List<Long> menuIds = sysUserMapper.getNavMenuIds(userId);   //先获取用户所有的菜单id
            if(menuIds.size() > 0){
                Collection<SysMenu> menus = sysMenuService.listByIds(menuIds);  //根据菜单id获取所有菜单
                for(SysMenu m : menus){
                    authority = authority + m.getPerm() +",";
                }
            }
            redisUtil.set("GrantedAuthority:"+user.getUsername(),authority,60*60);  //将权限信息保存到redis缓存
        }

        return authority;
    }

    //清除缓存中用户的权限信息
    @Override
    public void clearUserAuthorityInfo(String username) {
        redisUtil.del("GrantedAuthority:"+username);
    }

    //角色权限改变时,清除缓存中所有拥有此角色的用户权限信息
    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {
        List<SysUser> users = sysUserMapper.selectList(new QueryWrapper<SysUser>()
                .inSql("id", "select user_id from sys_user_role where role_id=" + roleId));
        users.forEach(u->{
            clearUserAuthorityInfo(u.getUsername());
        });
    }

    //菜单信息(如菜单权限编码)改变时，查出拥有此菜单的所有角色，再清除缓存中拥有这些角色的所有用户权限信息
    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        List<SysRole> roles = sysRoleMapper.selectList(new QueryWrapper<SysRole>()
                .inSql("id", "select role_id from sys_role_menu where menu_id=" + menuId));
        roles.forEach(r->{
            clearUserAuthorityInfoByRoleId(r.getId());
        });
    }

    //获取用户的角色信息
    @Override
    public void getUserRoles(SysUser user) {
        List<SysRole> roles = sysRoleMapper.selectList(new QueryWrapper<SysRole>()
                .inSql("id", "select role_id from sys_user_role where user_id=" + user.getId()));
        user.setRoles(roles);
    }
}
